﻿using System;
using Csla.Properties;
using System.Data.SqlClient;
using System.Data.Common;
using System.Collections;
using Csla;
using Csla.Core;
using Csla.Data;
using System.ComponentModel;
using System.Collections.Generic;
namespace BO
{
    [Serializable()]
    public abstract class BusinessListBaseEx<T, C> : Csla.BusinessBindingListBase<T, C>, IIsDirty
        where T : Csla.BusinessBindingListBase<T, C>
        where C : BusinessBaseEx,new ()
    {
        #region IsChild

        //[NotUndoable()]
        //protected override bool _isChild = false;  //tianyun internal

        /// <summary>
        /// Indicates whether this collection object is a child object.
        /// </summary>
        /// <returns>True if this is a child object.</returns>
        [Browsable(false)]
        public new bool IsChild
        {
            get { return _isChild; }
        }


        #endregion
        protected void DataPortal_Fetch(object criteria)
        {

            // retrieve data from db
            ListCriteria crit = (ListCriteria)criteria;

            using (DbConnection cn = DbFactory.GetConnection(Database.CompanyConnection))
            {
                cn.Open();
                using (DbCommand cm = cn.CreateCommand())
                {
                   // var p = ActiveRecordBase<C>.FindAll();
                    cm.CommandTimeout = 0;
                    var obj = new C();
                    var tableName = obj.GetTableName();
                    string selectClause = @" * ";
                    string fromClause =string.Format(" {0} {1} ", tableName,crit.CustomJoin);
                    string orderbyClause = "";
                    string whereClause = "";
                    string groupbyClause = "";
                    string havingClause = "";


                    if (crit.TopInt > 0)
                    {
                        cm.CommandText = String.Format("SELECT TOP {0} {1} FROM {2}", crit.TopInt, selectClause, fromClause);

                    }
                    else
                    {
                        cm.CommandText = String.Format("SELECT {0} FROM {1}", selectClause, fromClause);
                    }
                    if (whereClause.Trim().Length > 0)
                    {
                        cm.CommandText = String.Format("{0} WHERE {1}", cm.CommandText, whereClause);
                        if (crit.Filter.Trim().Length > 0)
                        {
                            cm.CommandText = String.Format("{0} AND {1}", cm.CommandText, crit.Filter);
                        }
                    }
                    else if (crit.Filter.Trim().Length > 0)
                    {
                        cm.CommandText = String.Format("{0} WHERE {1}", cm.CommandText, crit.Filter);
                    }
                    if (groupbyClause.Trim().Length > 0)
                    {
                        cm.CommandText = String.Format("{0} GROUP BY {1}", cm.CommandText, groupbyClause);
                    }
                    if (havingClause.Trim().Length > 0)
                    {
                        cm.CommandText = String.Format("{0} HAVING {1}", cm.CommandText, havingClause);
                    }
                    if (crit.SortString.Trim().Length > 0)
                    {
                        cm.CommandText = String.Format("{0} ORDER BY {1}", cm.CommandText, crit.SortString);
                    }
                    if (crit.Parameters != null)
                    {
                        foreach (SerSqlParameter param in crit.Parameters)
                        {
                            cm.Parameters.Add(param.ToSqlParameter());
                        }
                    }

                    using (SafeDataReader dr = new SafeDataReader(cm.ExecuteReader()))
                    {
                        if (crit.IsDistinct)
                        {
                            this.Fetch(dr, true);
                        }
                        else
                        {
                            this.Fetch(dr);

                        }
                        MarkClean();
                    }

                }
            }
        }

        protected override void DataPortal_Update()
        {
            // save data into db
            using (DbConnection cn = DbFactory.GetConnection(Database.CompanyConnection))
            {
                cn.Open();
                DbTransaction tr = cn.BeginTransaction(DbFactory.IsolationLevel);
                try
                {
                    Update(tr);
                    tr.Commit();
                }
                catch
                {
                    tr.Rollback();
                    throw;
                }
            }

        }

        // called to load data from the database
        public void Fetch(SafeDataReader dr)
        {
            Fetch(dr, false);
        }
        public void Fetch(SafeDataReader dr, bool IsCheckDuplicate)
        {
            RaiseListChangedEvents = false;
            while (dr.Read())
            {
                var obj = new C();
                obj.Get(dr);
                obj.SetHeader(this.Header);
                obj.ForceMarkAsChild();
                if (IsCheckDuplicate && this.Contains(obj))
                    continue;
                this.Add(obj);

            }

            RaiseListChangedEvents = true;
        }

        public virtual void Update(DbTransaction tr)
        {
            this.RaiseListChangedEvents = false;
            // update (thus deleting) any deleted child objects
            foreach (var deleted in DeletedList)
                deleted.Update(tr);

            // now that they are deleted, remove them from memory too
            DeletedList.Clear();

            // add/update any current child objects
            foreach (var obj in this)
                obj.Update(tr);

            this.RaiseListChangedEvents = true;
        }

        public int GetDelItemCount()
        {
            return this.DeletedList.Count;
        }

        public void Init()
        {
            this.Clear();
            this.DeletedList.Clear();
        }

        public virtual void MarkClean()
        {
            this.RaiseListChangedEvents = false;
            foreach (C child in this)
                if (child.IsDirty)
                    child.MarkClean();

            this.RaiseListChangedEvents = true;
        }

        public void AddChild(int index, C c)
        {
            if (this.AllowNew)
            {
                c.ForceMarkAsChild();
                this.Insert(index, c);
            }
        }

        public void AddChild(C c)
        {
            AddChild(this.Count, c);
        }

        public void AddToDeletedList(C c)
        {
            c.ForceMarkAsChild();
            base.DeletedList.Add(c);
        }


        public void MarkAsChild(bool value)  //tianyun
        {
            _isChild = value;
        }

        [NotUndoable()]
        BusinessBaseEx _header = null;

        public void SetHeader(BusinessBaseEx header)
        {

            _header = header;

            IEnumerator iEnum = this.GetEnumerator();

            while (iEnum.MoveNext())
            {
                BusinessBaseEx iBusinessBase = iEnum.Current as BusinessBaseEx;
                if (iBusinessBase != null)
                {
                    iBusinessBase.SetHeader(header);
                }
            }


        }

        public BusinessBaseEx Header
        {
            get { return _header; }
        }

        public void ClearnNotDirtyRecords()
        {
            if (!base.IsDirty)
            {
                this.Init();
            }
            else
            {
                for (int i = this.Count - 1; i >= 0; i--)
                {
                    var item = this[i];
                    if (!item.IsDirty && !item.IsDeleted)
                    {
                        this.Remove(item);
                        DeletedList.Remove(item);
                    }
                }
            }

        }

        public override bool IsSavable
        {
            get
            {
                return (IsDirty && IsValid && !IsBusy);
            }
        }

        public virtual BusinessListBaseEx<T, C> CopyToNew()
        {
            BusinessListBaseEx<T, C> retList = this.Clone() as BusinessListBaseEx<T, C>;
            foreach (C c in retList)
            {
                c.MarkNew();
            }
            return retList;
        }
    
        public T Save(bool IsCleanDirtyRecords)
        {
            if(this.Parent==null)
                _isChild = false;
            if(IsCleanDirtyRecords)
                ClearnNotDirtyRecords();
            var obj=  base.Save();
            MarkClean();
            return obj;
        }
        public override T Save()
        {
            return Save(false);
        }

        public virtual List<Object> ToModel()
        {
            var result = new List<object>();
            foreach (var obj in this)
            {
                result.Add(obj.ToModel());
            }
            return result;
            
        }
    }
}
